package com.googlecode.cswish.util.crosssite;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;

import com.googlecode.cswish.model.CrossSiteModel;
import com.googlecode.cswish.struts.ContextHolder;
import com.googlecode.cswish.struts.hibernate.ISite;
import com.googlecode.cswish.struts.spring.Executor;

/**
 * Resolve the type compatibility, see CrossSiteHashMap
 * 
 * @author Jerry
 *
 */
public class CrossSiteBoundedMap<K, V> extends BoundedConcurrentHashMap<K, V>
	implements CrossSiteModel<Map<K, V>> {

	private Map<String, Map<K, V>> siteMapMapping = new ConcurrentHashMap<String, Map<K, V>>();
	
	protected Map<K, V> initValue;
	
	protected Executor<Map<K, V>, Object> factory;
	
	public CrossSiteBoundedMap() {
	}
	
	public CrossSiteBoundedMap(Map<K, V> initValue) {
		this.initValue = initValue;
	}
	
	public CrossSiteBoundedMap(Map<K, V> initValue, Executor<Map<K, V>, Object> factory) {
		this.initValue = initValue;
		this.factory = factory;
	}
	
	private Map<K, V> getSiteMap() {
		String siteName = ContextHolder.get().getSiteName();
		if (siteName == null) {
			siteName = ISite.DEFAULT_NAME;
		}
		Map<K, V> siteMap = siteMapMapping.get(siteName);
		if (siteMap == null) {
			synchronized (siteMapMapping) {
				siteMap = siteMapMapping.get(siteName);
				if (siteMap == null) {
					if (factory == null) {
						if (initValue == null) {
							siteMap = new ConcurrentHashMap<K, V>();
						} else {
							siteMap = new ConcurrentHashMap<K, V>(initValue);
						}
					} else {
						siteMap = factory.execute(null);
						if (initValue != null) {
							siteMap.putAll(initValue);
						}
					}
					siteMapMapping.put(siteName, siteMap);
				}
			}
		}
		return siteMap;
	}
	
	public int size() {
		return getSiteMap().size();
	}

	public boolean isEmpty() {
		return getSiteMap().isEmpty();
	}

	public boolean containsKey(Object key) {
		return getSiteMap().containsKey(key);
	}

	public boolean containsValue(Object value) {
		return getSiteMap().containsValue(value);
	}

	public V get(Object key) {
		if (key == null) {
			return null;
		}
		return getSiteMap().get(key);
	}

	public V put(K key, V value) {
		return getSiteMap().put(key, value);
	}

	public V remove(Object key) {
		return getSiteMap().remove(key);
	}

	public void putAll(Map<? extends K, ? extends V> m) {
		getSiteMap().putAll(m);
	}

	public void clear() {
		getSiteMap().clear();
	}

	public Set<K> keySet() {
		return getSiteMap().keySet();
	}

	public Collection<V> values() {
		return getSiteMap().values();
	}

	public Set<java.util.Map.Entry<K, V>> entrySet() {
		return getSiteMap().entrySet();
	}

	public boolean equals(Object o) {
		return getSiteMap().equals(o);
	}

	public int hashCode() {
		return getSiteMap().hashCode();
	}

	@Override
	public void active(String site) {
		// TODO:
	}

	@Override
	public void passive(String site) {
		// TODO:
	}

	@Override
	public void destroy(String site) {
		siteMapMapping.remove(site);
	}

	@Override
	public Map<K, V> getModelBySite(String site) {
		return siteMapMapping.get(site);
	}
}
